<?php

namespace app\saas\service;

use app\common\configs\CommonData;
use app\common\model\trAdmin;
use app\common\model\trAdminSession;
use app\common\model\trSystemSet;
use app\common\util\ErrorCode;
use app\common\util\Tools;
use app\saas\model\trMall;

class WeService
{
    private $returnData;
    private $params;
    private $oauth_conf = [
        "getUserInfo" => "/oauth/getUserInfo", // 获取用户基本信息地址
        "changePassword" => "/oauth/modifyUserPwd", //修改密码地址
    ];
    private $key = "-----BEGIN PRIVATE KEY-----
MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAxWX0IJTMRxXoz0ap
/eKAaVKIKNv4O0JDaH/P/HkllziedndSRviDig/i676D+XdhZAk+EwWUAFfRc7eU
eX8o6wIDAQABAkBXzNdfPo/19lrNByNJV9vB/QGvGtg4k2qkKmV6aPA9aBs5SyNA
kk9c2s+rSYTK/poEblvJrgXXPqPD0ROSF8qBAiEA8C3yo87q+db19ZvFzU+8b53C
SWudLN5b+6OmaLG1TksCIQDSZppQ44hmoYkRxmo2plP9tY15eZoLOZ7/t5wysMRr
4QIgWg4QZYVHK6iDDrV6pDHaiMtRNvBHvbQeLys8URMY1SMCIGmnmGpyN/bBu2Ev
r/qNf7PxzX9orxBf+RYUj91sotZBAiEA3fp8+NHab3D9oc8/w04A7JHQn6Zojqbo
EcAzKI0tiM0=
-----END PRIVATE KEY-----"; // 私钥
    private $field = [
        "appId", "wsDomain", "id", "name", "secret", "sign", "token", "validTime", //"source"
    ]; // 填入数据库需要存储的表字段
    private $fieldMsg = [
        "appId" => "小程序appId", "wsDomain" => "接口地址", "id" => "应用ID", "name" => "应用名称",
        "secret" => "小程序密钥", "sign" => "签名", "token" => "用户信息token", "validTime" => "应用有效期",
        "source" => "系统来源"
    ];

    public function __construct($data, $param = null)
    {
        $this->returnData = $data;
        $this->params = $param;
        if(!empty($param["wsDomain"])){
            $this->oauth_conf["getUserInfo"] = $param["wsDomain"] . $this->oauth_conf["getUserInfo"];
            $this->oauth_conf["changePassword"] = $param["wsDomain"] . $this->oauth_conf["changePassword"];
        }
    }

    //获取用户信息
    public function getUserInfo($token, &$msg = ''){
        if(empty($token)){
            return false;
        }
        $currentUrl = $this->oauth_conf["getUserInfo"]; //获取用户基本信息地址
        list($server_token, $login_token) = explode("-", $token);
        $result = json_decode(Tools::curl($currentUrl, json_encode(["token" => $login_token])), true);
        if($result["code"] === 0 && isset($result["data"])){
            return $result["data"];
        }
        $msg = $result['msg'];
        return false;
    }

    // 初始化数据
    public function initializeData(){
        foreach ($this->field as $field) {
            if(!isset($this->params[$field])){
                return ErrorCode::code("params_not_exist", $this->fieldMsg[$field]);
            }
        }
        $sign = $this->getSign($this->params);
        if($sign != $this->params["sign"]){
            return ErrorCode::code("customized", "签名错误");
        }
        if(!$userData = $this->getUserInfo($this->params["token"], $msg)){
            return ErrorCode::code("customized", $msg);
        }
        $this->params["validTime"] = !is_numeric($this->params["validTime"]) ? strtotime($this->params["validTime"]) : $this->params["validTime"];
        $adminData = $this->checkAccount($userData);
        if(isset($adminData["code"])){
            return $adminData;
        }
        if(!$adminData["id"]){
            return ErrorCode::code("customized", "创建账号失败");
        }
        $mallData = $this->checkMall($adminData["id"]);
        if(isset($mallData["code"])){
            return $mallData;
        }
        if(!$mallData["id"]){
            return ErrorCode::code("customized", "创建商城失败");
        }
        $this->returnData["data"] = [
            "url" => request()->domain().request()->server("SCRIPT_NAME")."/saas/initialize/login",
            "version" => CommonData::VERSION
        ];
        return $this->returnData;
    }

    // 检查商城
    public function checkMall($managerId){
        $source = !empty($this->params["source"]) ? $this->params["source"] : null;
        $mallData = trMall::getFields("id,expired_time", ["instance_id" => $this->params["id"], "manager_id" => $managerId, "source" => $source], true, false);
        if(empty($mallData)){ // 没有要创建了
            $mallData = trMall::toAdd([
                "instance_id" => $this->params["id"], "manager_id" => $managerId, "name" => $this->params["name"],
                "expired_time" => $this->params["validTime"], "source" => $source
            ]);
            if(isset($mallData["code"])){
                return $mallData;
            }
            $mallData = Tools::transferFields($mallData->toArray());
            if($mallData){
                request()->mallData = ["id" => $mallData["id"]]; // 重置商城ID
                trSystemSet::toSave(["appId" => $this->params["appId"], "appSecret" => $this->params["secret"]], "wxAppConfig");
            }
        }
        if (!empty($mallData["expiredTime"]) && $mallData["expiredTime"] <= time()) {
            return ErrorCode::code("mall_expired");
        }
        return $mallData;
    }

    // 检查账号
    public function checkAccount($userData){
        $adminData = trAdmin::where("auth_id", $userData["uid"])->field("id,expired_time,mobile")->find();
        $isExistMobile = trAdmin::where("mobile", $userData["mobile"])->count();
        if(empty($adminData)){ // 没账号
            $checkAccount = trAdmin::where("username", $userData["account"])->field("id,auth_id,mobile")->find();
            if(!empty($checkAccount)){
                $updateData = ["auth_id" => $userData["uid"]];
                if(!$checkAccount["mobile"] && !$isExistMobile){
                    $updateData["mobile"] = $userData["mobile"];
                }
                trAdmin::where("id", $checkAccount["id"])->update($updateData);
                $adminData = trAdmin::where("auth_id", $userData["uid"])->field("id,expired_time,mobile")->find();
            }else { // 创建新账号
                $salt = local_salt();
                $data = [
                    "auth_id" => $userData["uid"], "avatar" => $userData["avatarUrl"], "username" => $userData["account"],
                    "password" => generate_password($userData["account"], $salt), "salt" => $salt,
                    "app_count" => 1, "remark" => "平台自动创建", "type" => 3, "expired_time" => null, "create_time" => time()
                ];
                if(!$isExistMobile){
                    $data["mobile"] = $userData["mobile"];
                }
                $adminModel = trAdmin::create($data);
                $adminData = $adminModel->toArray();
            }
        }else{
            if(!$adminData["mobile"] && !$isExistMobile){
                trAdmin::where("id", $adminData["id"])->update(["mobile" => $userData["mobile"]]);
            }
        }
        if(!empty($adminData["expired_time"]) && $adminData["expired_time"] <= time()){
            return ErrorCode::code('account_expired');
        }
        return $adminData;
    }

    // 自动登录
    public function toLogin(){
        if(!isset($this->params["loginToken"])){
            return ErrorCode::code("params_not_exist", "免登录token");
        }
        if(!isset($this->params["id"])){
            return ErrorCode::code("params_not_exist", "实例应用ID");
        }
        if(!$userData = $this->getUserInfo($this->params["loginToken"], $msg)){
            return ErrorCode::code("customized", $msg);
        }
        $adminData = $this->checkAccount($userData);
        if(isset($adminData["code"])){
            return $adminData;
        }
        if(!$adminData["id"]){
            return ErrorCode::code("customized", "登录失败");
        }
        $this->params["source"] = !empty($this->params["source"]) ? $this->params["source"] : "";
        $mallData = trMall::getFields("id,expired_time", [
            "instance_id" => $this->params["id"], "manager_id" => $adminData["id"], "source" => $this->params["source"]
        ], true, false);
        if(empty($mallData)){
            return ErrorCode::code("customized", "商城不存在，请联系管理员");
        }
        if (!empty($mallData["expiredTime"]) && $mallData["expiredTime"] <= time()) {
            return ErrorCode::code("mall_expired");
        }
        $data = trAdmin::getAdminInfo($adminData["id"], "id,username,type,status,expired_time");
        $sessionExpireTime = config("session_expire");
        $data["loginIp"] = Tools::get_client_ip();
        $data["isSaas"] = "1"; // saas端已登陆
        $data["tokenTime"] = time() + $sessionExpireTime;
        if(empty($sessionId = cache("NotLoginToken_{$adminData["id"]}_{$mallData["id"]}"))){
            $sessionId = trAdmin::generateSessionId();
            //保存token
            $result = trAdminSession::add([
                "admin_id" => $adminData["id"], "session_id" => $sessionId, "login_ip" => $data["loginIp"], "create_time" => time(),
                "expire_time" => $data["tokenTime"], "is_saas" => $data["isSaas"]
            ]);
            if (isset($result['code'])) {
                return $result;
            }
            cache("NotLoginToken_{$adminData["id"]}_{$mallData["id"]}", $sessionId, $sessionExpireTime);
        }else{
            $result = trAdminSession::doUpdate(["expire_time" => $data["tokenTime"]], [
                ["admin_id", '=', $adminData["id"]], ["session_id", '=', $sessionId], ["expire_time", ">", time()]
            ]);
            if(empty($result)){
                $sessionId = trAdmin::generateSessionId();
                //保存token
                $result = trAdminSession::add([
                    "admin_id" => $adminData["id"], "session_id" => $sessionId, "login_ip" => $data["loginIp"], "create_time" => time(),
                    "expire_time" => $data["tokenTime"], "is_saas" => $data["isSaas"]
                ]);
                if (isset($result['code'])) {
                    return $result;
                }
                cache("NotLoginToken_{$adminData["id"]}_{$mallData["id"]}", $sessionId, $sessionExpireTime);
            }
        }
        cache("SaaS_" . $sessionId, $data, $sessionExpireTime); //缓存用户信息
        $redirect = request()->domain()."/index.html#/workbench/index?SaaSToken={$sessionId}&SaaSId={$mallData["id"]}";
        if(!request()->server("IS_SCF")) {
            header('Location: ' . $redirect);exit;
        }
        $js = " <script language = 'javascript' type = 'text/javascript' >";
        $js .= "window.location.href ='{$redirect}'";
        $js .= " </script > ";
        return $js;
    }

    public function getInfo(){
        if(!isset($this->params["loginToken"])){
            return ErrorCode::code("params_not_exist", "免登录token");
        }
        if(!isset($this->params["id"])){
            return ErrorCode::code("params_not_exist", "实例应用ID");
        }
        if(!$userData = $this->getUserInfo($this->params["loginToken"], $msg)){
            return ErrorCode::code("customized", $msg);
        }
        $adminData = $this->checkAccount($userData);
        if(isset($adminData["code"])){
            return $adminData;
        }
        if(!$adminData["id"]){
            return ErrorCode::code("customized", "登录失败");
        }
        $this->params["source"] = !empty($this->params["source"]) ? $this->params["source"] : "";
        $mallData = trMall::getFields("id", [
            "instance_id" => $this->params["id"], "manager_id" => $adminData["id"], "source" => $this->params["source"]
        ], true, false);
        if(empty($mallData)){
            return ErrorCode::code("customized", "商城不存在，请联系管理员");
        }
        $this->returnData["data"] = ["url" => request()->domain()."/index.html#/login?system={$mallData["id"]}"];
        return $this->returnData;
    }

    // 修改到期时间
    public function toModifyTime(){
        if(!isset($this->params["token"])){
            return ErrorCode::code("params_not_exist", "免登录token");
        }
        if(!isset($this->params["id"])){
            return ErrorCode::code("params_not_exist", "实例应用ID");
        }
        if(!$userData = $this->getUserInfo($this->params["token"], $msg)){
            return ErrorCode::code("customized", $msg);
        }
        $adminData = $this->checkAccount($userData);
        if(isset($adminData["code"])){
            return $adminData;
        }
        if(!$adminData["id"]){
            return ErrorCode::code("customized", "账号信息不存在");
        }
        $this->params["source"] = !empty($this->params["source"]) ? $this->params["source"] : "";
        $mallData = trMall::getFields("id", ["instance_id" => $this->params["id"], "manager_id" => $adminData["id"], "source" => $this->params["source"]], true, false);
        if(empty($mallData)){
            return ErrorCode::code("customized", "商城不存在，请联系管理员");
        }
        $this->params["validTime"] = !is_numeric($this->params["validTime"]) ? strtotime($this->params["validTime"]) : $this->params["validTime"];
        $res = trMall::doUpdate(["expired_time" => $this->params["validTime"]], ["id" => $mallData["id"]]);
        if($res || $res === 0){
            return $this->returnData;
        }else{
            $this->returnData = ErrorCode::$errorCode["fail"];
            $this->returnData["msg"] = "修改成功";
            return $this->returnData;
        }
    }

    // 修改商城基本信息
    public function updateInfo(){
        foreach (["id", "name", "appId", "secret", "uid", "source", "sign"] as $field) {
            if(!isset($this->params[$field])){
                return ErrorCode::code("params_not_exist", $field);
            }
            $this->params[$field] = trim($this->params[$field]);
        }
        $sign = $this->getSign($this->params);
        if($sign != $this->params["sign"]){
            return ErrorCode::code("customized", "签名错误");
        }
        $adminId = trAdmin::where("auth_id", $this->params["uid"])->value("id");
        $mallData = trMall::getFields("id", ["instance_id" => $this->params["id"], "manager_id" => $adminId, "source" => $this->params["source"]], true, false);
        if(empty($mallData)){
            return ErrorCode::code("customized", "商城不存在，请联系管理员");
        }
        trMall::doUpdate(["name" => $this->params["name"]], ["id" => $mallData["id"]]);
        request()->mallData = ["id" => $mallData["id"]]; // 重置商城ID
        trSystemSet::toSave(["appId" => $this->params["appId"], "appSecret" => $this->params["secret"]], "wxAppConfig");
        return $this->returnData;
    }

    // 生成签名
    public function getSign($params){
        unset($params['sign']);
        ksort($params);
        reset($params);

        $pairs = array();
        foreach ($params as $k => $v) {
            if(!empty($v)){
                $pairs[] = "$k=$v";
            }
        }
        $arr = implode('&', $pairs);
        $priKeyId = openssl_pkey_get_private($this->key);
        $signature = '';
        openssl_sign($arr, $signature, $priKeyId, OPENSSL_ALGO_MD5);
        openssl_free_key($priKeyId);
        return base64_encode($signature);
    }
}
